/**
 * Copyright (c) 2019 Coder League
 * All rights reserved.
 *
 * File：SessionManager.java
 * History:
 *         2019年5月20日: Initially created, Chrise.
 */
package club.coderleague.ilsp.common.session;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.session.data.redis.RedisOperationsSessionRepository;

import club.coderleague.ilsp.common.domain.beans.UserSession;
import club.coderleague.ilsp.service.users.UserService;

/**
 * 会话管理器。
 * @author Chrise
 */
public class SessionManager {
	private static final String SESSION_KEY_PREFIX = "spring:session:sessions:";
	private static final String SESSION_ATTR_KEY = "sessionAttr:" + UserSession.SESSION_KEY;
	
	@Autowired
	private UserService userService;
	@Autowired
	private ThreadPoolTaskScheduler taskScheduler;
	@Autowired
	private RedisOperationsSessionRepository sessionRepository;
	private List<String> sessionCache;
	
	/**
	 * 会话管理器构造方法。
	 */
	public SessionManager() {
		this.sessionCache = new ArrayList<String>();
	}
	
	/**
	 * 加入会话管理器。
	 * @author Chrise 2019年5月20日
	 * @param sessionId 会话标识。
	 */
	public void add(String sessionId) {
		synchronized (this) {
			if (!this.sessionCache.contains(sessionId)) 
				this.sessionCache.add(sessionId);
		}
	}
	
	/**
	 * 从会话管理器移出。
	 * @author Chrise 2019年5月20日
	 * @param sessionId 会话标识。
	 */
	public void remove(String sessionId) {
		synchronized (this) {
			this.sessionCache.remove(sessionId);
		}
	}
	
	/**
	 * 刷新用户会话。
	 * @author Chrise 2019年5月21日
	 * @param userId 用户标识。
	 */
	public void refresh(long userId) {
		this.taskScheduler.schedule(new AuthoritieRefreshTask(userId), new Date(System.currentTimeMillis() + 1000L));
	}
	
	/**
	 * 刷新授权。
	 * @author Chrise 2019年5月21日
	 * @param userId 用户标识。
	 */
	private void refreshAuthorities(long userId) {
		String[] sessions = {};
		synchronized (this) {
			sessions = this.sessionCache.toArray(sessions);
		}
		if (sessions.length <= 0) return;
		
		HashOperations<Object, Object, Object> hash = this.sessionRepository.getSessionRedisOperations().opsForHash();
		for (String session : sessions) {
			String key = SESSION_KEY_PREFIX + session;
			
			UserSession us = (UserSession)hash.get(key, SESSION_ATTR_KEY);
			if (us != null && us.getUserid() == userId) {
				List<String> authorities = this.userService.queryAuthorities(userId);
				us.setAuthorities(authorities);
				
				hash.put(key, SESSION_ATTR_KEY, us);
			}
		}
	}
	
	/**
	 * 授权刷新任务。
	 * @author Chrise
	 */
	private class AuthoritieRefreshTask implements Runnable {
		private final Logger LOGGER = LoggerFactory.getLogger(AuthoritieRefreshTask.class);
		
		private long userId;
		
		/**
		 * 授权刷新任务构造方法。
		 * @param userId 用户标识。
		 */
		public AuthoritieRefreshTask(long userId) {
			this.userId = userId;
		}
		
		/**
		 * @see java.lang.Runnable#run()
		 */
		@Override
		public void run() {
			try {
				refreshAuthorities(this.userId);
			} catch (Exception e) {
				LOGGER.error(e.getMessage(), e);
			}
		}
	}
}
